from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import numpy as np
import cv2 as cv
import requests
import base64
import os,time
import json
import traceback
from dao import SQLiteDb

class caseiDriver(object):

    __city = 1
    __city_name = ''
    __city_page = 1
    __unit = 1
    __unit_name = ''
    __unit_no = ''
    __unit_page = 1
    __person = 1
    __person_name = ''
    __person_page = 1

    user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'

    def __init__(self, url, time2wait=10):

        if not os.path.exists('./data'):
            os.makedirs('./data')

        self.dao = SQLiteDb('./data/casei.db')

        chrome_options = Options()
        #chrome_options.add_argument("--proxy-server=http://%s" % prt)
        chrome_options.add_argument('user-agent="%s"' % self.user_agent)
        chrome_options.add_argument('disable-infobars')
        chrome_options.add_argument('disable-blink-features=AutomationControlled')
        ex_path = 'C:\Program Files\Google\Chrome\Application\chromedriver.exe'
        self.browser = webdriver.Chrome(executable_path= ex_path, chrome_options=chrome_options)
        self.browser.delete_all_cookies()
        self.browser.set_window_size(1432,884)
        self.browser.implicitly_wait(time2wait)
        self.browser.get(url)
        self.wait = WebDriverWait(self.browser, time2wait)

    def __del__(self):
        self.browser.quit()

    def __cityPage(self):
        self.browser.get('http://219.141.208.170/casei/register/personPublicAction!getProvincePersonInfoForm.action')
        try:
            li = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="tt"]/tbody/tr[%s]/td[2]/a' % self.__city)))
            self.__city_name = li.text
            print(self.__city_name)
            self.__city = self.__city + 1
            self.__unit = 1
            self.__unit_page = 1
            self.__person = 1
            self.__person_page = 1
            li.click()
            self.__unitPage()
        except Exception as e:
            if self.__city > 1:
                try:
                    np = self.browser.find_element_by_link_text('下一页')
                    self.__city = 1
                    np.click()
                    self.__cityPage()
                except Exception as e1:
                    print('遍历完成')

    def __unitPage(self):
        self.browser.get(
            'http://219.141.208.170/casei/register/personPublicAction!toNoTopUnitPersonInfoForm.action?province=%s&page=%s&rows=20' % (
                self.__city_name, self.__unit_page))
        try:
            li = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="tbody"]/tr[%s]/td[2]/a' % self.__unit)))
            print('+++', li.text)
            self.__unit_name = li.text
            self.__unit_no = li.get_attribute('onclick').split("'")[1]
            self.__unit = self.__unit + 1
            self.__person = 1
            self.__person_page = 1
            li.click()
            self.__personPage()
        except Exception as e:
            print(str(e))
            if self.__unit > 1:
                try:
                    np = self.browser.find_element_by_link_text('下一页')
                    self.__unit = 1
                    self.__unit_page = self.__unit_page + 1
                    np.click()
                    self.__unitPage()
                except Exception as e1:
                    print('返回城市列表')
                    self.__cityPage()

    def __personPage(self):
        self.browser.get(
            'http://219.141.208.170/casei/register/personPublicAction!toNoTopPersonInfoForm.action?unitNo=%s&province=%s&page=%s&rows=20' % (
               self.__unit_no, self.__city_name, self.__person_page))
        time.sleep(2)
        try:
            pi = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="tt"]/tbody/tr[%s]/td[3]' % self.__person)))
            self.__person_name = pi.text
            print(self.__city_name, '---', self.__unit_name, '---', self.__person_name)
            tm = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
            self.dao.addPerson(self.__city_name, self.__unit_name, self.__person_name, '', '', tm)

            li = self.wait.until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[1]/form[1]/table/tbody/tr[%s]/td[7]/a' % self.__person)))
            li.click()
            self.__personView()

        except Exception as e:
            # print(traceback.format_exc())
            if self.__person > 1:
                try:
                    np = self.browser.find_element_by_link_text('下一页')
                    self.__person = 1
                    self.__person_page = self.__person_page + 1
                    np.click()
                    self.__personPage()
                except Exception as e1:
                    print('退回单位列表')
                    self.__unitPage()

    def __personView(self):
        time.sleep(3)
        if self.__slideDrag() is True:
            has_rs = False
            rs_str = ''
            try:
                pname = self.browser.find_element_by_xpath('/html/body/table/tbody/tr[2]/td[2]')
                print(pname.text, '-CHECKIN')
                tds = self.browser.find_elements_by_tag_name('td')
                for td in tds:
                    if 'RS' in td.text:
                        has_rs = True
                        rs_str = rs_str + '-RS'
                    if 'DS' in td.text:
                        has_rs = True
                        rs_str = rs_str + '-DS'
                    if 'DTY' in td.text:
                        has_rs = True
                        rs_str = rs_str + '-DTY'
                    if 'gls' in td.text:
                        has_rs = True
                        rs_str = rs_str + '-gls'
                    if 'GS' in td.text:
                        has_rs = True
                        rs_str = rs_str + '-GS'
                    if 'QZY' in td.text:
                        has_rs = True
                        rs_str = rs_str + '-QZY'
                    if 'RQ' in td.text:
                        has_rs = True
                        rs_str = rs_str + '-RQ'
                    if 'GD' in td.text:
                        has_rs = True
                        rs_str = rs_str + '-GD'

                # btn = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'next_step')))
                # btn.click()
            except Exception as e:
                pass

            if has_rs is True:
                # 更新证书状态
                self.dao.updatePerson(self.__unit_name, self.__person_name, rs_str, 'yes')
                print('---', rs_str)
        else:
            print('验证码未通过')

        self.__person = self.__person + 1
        self.__personPage()

    def __slideDrag(self):
        for attempt in range(3):
            try:
                EC.text_to_be_present_in_element((By.CLASS_NAME, r'verify-msg'), r'向右滑动完成验证')
                # 获取背景图与滑动块图片js读取更快
                idx = int(self.__person) - 1
                background_image = self.browser.execute_script('return $("#captcha%s").find(".backImg").attr("src").replace("data:image/png;base64,", "")' % idx)
                slider_image = self.browser.execute_script('return $("#captcha%s").find(".bock-backImg").attr("src").replace("data:image/png;base64,", "")' % idx)
                # background_image_url = self.browser.find_elements_by_class_name('backImg')[idx].get_attribute('src')
                # slider_image_url = self.browser.find_elements_by_class_name('bock-backImg')[idx].get_attribute('src')
                # background_image = background_image_url.replace('data:image/png;base64,', '')
                # slider_image = slider_image_url.replace('data:image/png;base64,', '')
                # 云打码每次1分钱 准确率高
                # distance = self.__slide_verify(slider_image, background_image)
                distance = self.__slide_match(slider_image, background_image)
                # 等比例缩放滑动距离 400 / 310
                distance = int(distance * 1.29) - 2
                # print(distance)
                if int(distance) < 1:
                    return False

                btn = self.browser.find_elements_by_class_name('verify-move-block')[idx]
                ActionChains(self.browser).drag_and_drop_by_offset(btn, xoffset=distance, yoffset=0).perform()
            except Exception as e:
                pass

            time.sleep(3)
        return True

    def __slide_match(self, slider_image, background_image):
        background_image_path = 'background_image' + '.png'
        with open(background_image_path, 'wb') as f:
            f.write(base64.b64decode(background_image))
        slider_image_path = 'slider_image' + '.png'
        with open(slider_image_path, 'wb') as f:
            f.write(base64.b64decode(slider_image))
        time.sleep(1)

        # 读取图片
        background = cv.imread(background_image_path)
        slider = cv.imread(slider_image_path)
        '''
        background_raw = np.fromstring(background_image, np.uint8)
        background = cv.imdecode(background_raw, cv.IMREAD_COLOR)
        slider_raw = np.fromstring(slider_image, np.uint8)
        slider = cv.imdecode(slider_raw, cv.IMREAD_COLOR)
        '''
        # 灰度处理图片 图片只有白黑
        background = cv.cvtColor(background, cv.COLOR_BGR2GRAY)
        slider = cv.cvtColor(slider, cv.COLOR_BGR2GRAY)
        # 去除白色部分 获取滑块正常大小
        slider = slider[slider.any(1)]

        # 进行相似度匹配返回坐标数组
        result = cv.matchTemplate(background, slider, cv.TM_CCOEFF_NORMED)

        # 获取相似度最高像素坐标 x 是像素高度 y 是像素距离
        x, y = np.unravel_index(result.argmax(), result.shape)
        return y


    def __slide_verify(self, slide_image, background_image, verify_type="20101"):
        # 滑块类型
        # 通用双图滑块  20111
        payload = {
            "slide_image": slide_image,
            "background_image": background_image,
            "token": "q_rPUre8Wm1UD89n_pPi9sLibMsVyl6KJ",
            "type": verify_type
        }
        headers = {
            'Content-Type': 'application/json'
        }
        resp = requests.post('http://api.jfbym.com/api/YmServer/customApi', headers=headers, data=json.dumps(payload))
        # print(resp.text)
        res = resp.json()
        if res['code'] == 10000:
            return int(res['data']['data'])
        else:
            print(res['msg'])
            return 0

    def run(self):
        self.__cityPage()

if __name__ == '__main__':
    drv = caseiDriver('http://219.141.208.170/casei/register/personPublicAction!getProvincePersonInfoForm.action')
    drv.run()